﻿using Microsoft.Win32;
using System.ComponentModel;
using System.Drawing;

namespace System.Windows.Forms
{
	/// <summary>
	/// Represents an expanded Windows list view control, which displays a collection of items that can be displayed using one of four different views. Added support for DataSource, columns, and groups.
	/// </summary>
	public partial class ListViewEx : ListView
	{
		private Image watermarkImage;

		/// <summary>
		/// Initializes a new instance of the <see cref="ListViewEx"/> class.
		/// </summary>
		public ListViewEx()
		{
			this.ListViewItemSorter = new System.Windows.Forms.ListViewColumnSorter();
		}

		/// <summary>
		/// Gets or sets the watermark.
		/// </summary>
		/// <value>
		/// The watermark.
		/// </value>
		[DefaultValue((Image)null), Category("Appearance")]
		public Image Watermark
		{
			get { return watermarkImage; }
			set
			{
				watermarkImage = value;
				if (base.IsHandleCreated && value != null)
				{
					var bki = new NativeMethods.LVBKIMAGE(new Bitmap(value), true, true);
					NativeMethods.SendMessage(this.Handle, NativeMethods.ListViewMessage.SetBkImage, 0, bki);
				}
			}
		}

		/// <summary>
		/// Measures the width of the text using the current font.
		/// </summary>
		/// <param name="text">The text to measure.</param>
		/// <returns>Width of text in pixels.</returns>
		public int MeasureTextWidth(string text)
		{
			return NativeMethods.SendMessage(this.Handle, (uint)NativeMethods.ListViewMessage.GetStringWidth, IntPtr.Zero, text).ToInt32();
		}

		internal void RecreateHandleInternal()
		{
			if (base.IsHandleCreated && (this.StateImageList != null))
				SendMessage(NativeMethods.ListViewMessage.Update, -1, IntPtr.Zero);
			base.RecreateHandle();
		}

		/// <summary>
		/// Clean up any resources being used.
		/// </summary>
		/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
		protected override void Dispose(bool disposing)
		{
			(this as System.Configuration.IPersistComponentSettings).SaveComponentSettings();
			base.Dispose(disposing);
		}

		/// <summary>
		/// </summary>
		/// <param name="e">An <see cref="T:System.EventArgs" /> that contains the event data.</param>
		protected override void OnHandleCreated(EventArgs e)
		{
			base.OnHandleCreated(e);
			this.OnHandleCreated_Groups(e);
			this.OnHandleCreated_Columns(e);
		}

		/// <summary>
		/// Overrides <see cref="M:System.Windows.Forms.Control.WndProc(System.Windows.Forms.Message@)" />.
		/// </summary>
		/// <param name="m">The Windows <see cref="T:System.Windows.Forms.Message" /> to process.</param>
		[System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityAction.LinkDemand, Flags = System.Security.Permissions.SecurityPermissionFlag.UnmanagedCode)]
		protected override void WndProc(ref Message m)
		{
			WndProc_Columns(ref m);
			switch (m.Msg)
			{
				case 0x0200: // WM_MOUSEMOVE
					break;

				case 0x0202: // WM_LBUTTONUP
				//base.DefWndProc(ref m);
				//break;
				default:
					base.WndProc(ref m);
					break;
			}
		}

		private int SendMessage(NativeMethods.ListViewMessage msg, int wParam, IntPtr lParam)
		{
			return NativeMethods.SendMessage(this.Handle, (uint)msg, (IntPtr)wParam, lParam).ToInt32();
		}

		private void UpdateListViewItemsLocations()
		{
			if (((!this.VirtualMode && base.IsHandleCreated) && this.AutoArrange))
			{
				try
				{
					this.BeginUpdate();
					SendMessage(NativeMethods.ListViewMessage.Update, -1, IntPtr.Zero);
				}
				finally
				{
					this.EndUpdate();
				}
			}
		}

		internal void UpdateStateToListView(int index)
		{
			var lvItem = new NativeMethods.LVITEM(index, 0, NativeMethods.ListViewItemMask.State);
			var i = this.Items[index];
			if (i.Selected)
				lvItem.SetState(NativeMethods.ListViewItemState.Selected, true);
			if (i.StateImageIndex > -1)
				lvItem.StateImageIndex = (uint)i.StateImageIndex;
			//if (this.GroupsEnabled)
				// TODO: Figure out a way to add to group // lvItem.GroupId = this.GetGroupId(i.Group);
			NativeMethods.SendMessage(this.Handle, NativeMethods.ListViewMessage.SetItem, 0, lvItem);
		}

		private bool ComctlSupportsVisualStyles
		{
			get { return Application.RenderWithVisualStyles; }
		}
	}
}